package com.apes.framework.plugin.workflow.parser.model;

import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.esb.processor.mapping.Mapping;
import com.apes.framework.plugin.esb.processor.mapping.parser.model.Config;
import com.apes.framework.util.CacheUtil;
import com.apes.framework.util.RopUtil;
import com.apes.framework.util.Tools;
import com.apes.oap.RopContext;
import com.apes.oap.impl.SimpleRopRequestContext;
import com.apes.oap.session.RopSessionHolder;
import lombok.Data;
import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 功能：node元模型
 *
 * @author xul
 * @create 2018-06-30 14:36
 */
@Data
public class Node {
    private static Map<String, String> formEsbIds = new LinkedCaseInsensitiveMap();

    private String id;

    private String remark;

    private boolean automatic = false;

    private String auth;

    /***
     * 界面是否可编辑
     */
    private boolean editable = false;

    /***
     * 界面是否抄送
     */
    private boolean carbonCopy = true;

    /**
     * 开始事件（start），任务（task），结束事件（end）
     */
    private String name;

    /**
     * 表单信息
     */
    private Form form = null;

    /**
     * 任务执行的入参mapping
     */
    private Config config = null;

    /**
     * 待办的内容mapping
     */
    private Config content = null;

    List<String> beforeEsbIds = new ArrayList();

    List<String> afterEsbIds = new ArrayList();

    List<Group> groups = new ArrayList();

    List fields = new ArrayList();

    public List<String> getEsbIds() {
        List<String> esbIds = new ArrayList<>();
        esbIds.addAll(beforeEsbIds);
        esbIds.addAll(afterEsbIds);
        return esbIds;
    }

    /**
     * 功能：任务执行的入参mapping
     *
     * @param data
     * @return
     */
    public <T> T convert(Object data) {
        if (config == null) return null;
        return (T) mapping(config, data);
    }

    /**
     * 功能：待办的内容mapping
     *
     * @param data
     * @return
     */
    public <T> T content(Object data) {
        if (content == null) return null;
        return (T) mapping(content, data);
    }

    private <T> T mapping(Config config, Object data) {
        if (config == null) return null;
        return (T) new Mapping().convert(config, data);
    }

    /**
     * 功能：取待办人
     *
     * @return
     */
    public List<Map> getUsers(Map body, String branchId, String workPostId) {
        List<Map> users = new ArrayList();
        Map context = createContext(body);
        this.groups.stream().filter(group -> execute(StringUtils.isEmpty(group.getTest()) ? "1 == 1" : group.getTest(), context))
                .forEach(group -> group.getUsers().stream().forEach(user -> users.addAll(user.getUsers(branchId, workPostId))));
        return users;
    }

    private Map createContext(Map body) {
        Map context = new HashMap();
        context.putAll(body);
        RopContext ropContext = RopUtil.getRopContext();
        SimpleRopRequestContext ropRequestContext = new SimpleRopRequestContext(ropContext);
        ropRequestContext.addSession(RopSessionHolder.get());
        SimpleRequest simpleRequest = new SimpleRequest();
        simpleRequest.setRopRequestContext(ropRequestContext);
        simpleRequest.setData(body);
        context.put("request", simpleRequest);
        return context;
    }

    private boolean execute(String express, Map context) {
        Object o = CacheUtil.getEngine().execute(express, context, e -> String.format("表达式：%s 在上下文：%s 中执行错误！", express, context));
        if (!(o instanceof Boolean)) {
            throw new RuntimeException(String.format("表达式：%s" + " 定义错误！", express));
        }
        return (boolean) o;
    }

    public void addFormEsbId(String formId, String esbId) {
        formEsbIds.put(formWithEsbId(formId, esbId), esbId.trim());
    }

    private static String formWithEsbId(String formId, String esbId) {
        String f = formId.startsWith("/") ? formId : "/" + formId;
        return f.trim() + "#" + esbId.trim();
    }

    public static boolean exist(String formId, String esbId) {
        if (Tools.isNull(formId) || Tools.isNull(esbId)) return false;
        String key = formWithEsbId(formId, esbId);
        return formEsbIds.containsKey(key);
    }

}
